/*******************************************************************************
 * Copyright (c) 2004, 2007 Mylyn project committers and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/

package org.eclipse.mylyn.rememberthemilk.core;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.mylyn.rememberthemilk.core.RTMAttributeMapper.Attribute;
import org.eclipse.mylyn.rememberthemilk.core.client.RTMClient;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
import org.eclipse.mylyn.tasks.core.RepositoryResponse;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.ITask.PriorityLevel;
import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData;
import org.eclipse.mylyn.tasks.core.data.TaskData;

import com.mdt.rtm.data.RtmTask;
import com.mdt.rtm.data.RtmTaskSeries;
import com.mdt.rtm.data.RtmTask.Priority;

/**
 * @author Steffen Pingel
 */
public class RTMTaskDataHandler extends AbstractTaskDataHandler {

	private static final String CC_DELIMETER = ", ";

	private final TaskAttributeMapper attributeFactory = null;

	private final RTMRepositoryConnector connector;

	public RTMTaskDataHandler(RTMRepositoryConnector connector) {
		this.connector = connector;
	}

	@Override
	public TaskAttributeMapper getAttributeMapper(TaskRepository taskRepository) {
		return new RTMAttributeMapper(taskRepository);
	}

	@Override
	public boolean initializeTaskData(TaskRepository repository, TaskData data, ITaskMapping initializationData,
			IProgressMonitor monitor) throws CoreException {
		try {
			RTMClient client = connector.getClientManager().getRepository(
					repository);
			client.updateAttributes(false);
			createDefaultAttributes(data, client);
		} catch (Exception e) {
			throw new CoreException(RTMLog.createStatus(e, repository.getUrl()));
		}
		return true;
	}

	@Override
	public RepositoryResponse postTaskData(TaskRepository repository,
			TaskData taskData, Set<TaskAttribute> oldAttributes,
			IProgressMonitor monitor) throws CoreException {
		String taskSeriesId ="";
		RTMClient client = connector.getClientManager().getRepository(repository);

		client.createTimeline();

		String listId = taskData.getRoot().getAttribute(
				Attribute.TASKLIST.getRTMKey()).getValue();


		boolean isNew = taskData.isNew();
		if (isNew) {
			String name = taskData.getRoot().getAttribute(Attribute.NAME.getRTMKey()).getValue();
			RtmTaskSeries series = client.createNewTask(listId, name);
			taskData = createTaskDataFromSeries(series, repository);
		}

		taskSeriesId = taskData.getRoot().getAttribute(Attribute.TASKSERIE.getRTMKey()).getValue();
		String taskId = taskData.getRoot().getAttribute(Attribute.TASKID.getRTMKey()).getValue();

		RtmTaskSeries series = client.getRTMTaskSerie(taskSeriesId);
		if (!series.getListId().equals(listId)) {
			client.updateTaskList(series.getListId(), listId, taskSeriesId, taskId);
		}


		for (TaskAttribute attr : taskData.getRoot().getAttributes().values()) {
			if (attr.getId().equals(Attribute.PRIORITY.getRTMKey())) {
				TaskAttribute newPriority = taskData.getRoot().getAttribute(Attribute.PRIORITY.getRTMKey());
				PriorityLevel priority = ITask.PriorityLevel.fromString(newPriority.getValue());
				Priority priorityValue;
				switch (priority) {
				case P1:
					priorityValue = RtmTask.Priority.High;
					break;
				case P2:
					priorityValue = RtmTask.Priority.Medium;
					break;
				case P4:
					priorityValue = RtmTask.Priority.Low;
					break;
				default:
					priorityValue = RtmTask.Priority.None;
					break;
				}
				client.updateTaskPriority(listId, taskSeriesId, taskId, priorityValue);
			} else if(attr.getId().equals(Attribute.STATUS.getRTMKey())) {
				TaskAttribute newStatus = taskData.getRoot().getAttribute(Attribute.STATUS.getRTMKey());
				boolean complete = false;
				if("complete".equals(newStatus.getValue())) {
					complete = true;
				}
				client.updateTaskStatus(listId, taskSeriesId, taskId, complete);
			} else if(attr.getId().equals(Attribute.TAGS.getRTMKey())) {
				client.updateTags(attr.getValue(), listId, taskSeriesId, taskId);
			} else if (attr.getId().equals(Attribute.NAME.getRTMKey()) && !isNew) {
				TaskAttribute newName = taskData.getRoot().getAttribute(Attribute.NAME.getRTMKey());
				client.updateTaskName(listId, taskSeriesId, taskId, newName.getValue());
			}
		}
		return new RepositoryResponse(ResponseKind.TASK_UPDATED, taskSeriesId);
	}

	public TaskData createTaskDataFromSeries(RtmTaskSeries series, TaskRepository repository) {
		TaskData data = null;
		String taskId;
		if (series == null) {
			taskId = "";
		} else {
			taskId = series.getId();
		}
		data = new TaskData(getAttributeMapper(repository), RTMCorePlugin.REPOSITORY_KIND,
				repository.getUrl(), taskId);
		RTMClient client = connector.getClientManager().getRepository(repository);
		createDefaultAttributes(data, client);
		updateAttributes(data, series);
		return data;
	}

	private void createDefaultAttributes(TaskData data, RTMClient client) {
		createDefaultAttribute(data, Attribute.NAME);
		createDefaultAttribute(data, Attribute.COMPLETED);
		createDefaultAttribute(data, Attribute.PRIORITY);
		createDefaultAttribute(data, Attribute.CREATED);
		createDefaultAttribute(data, Attribute.MODIFIED);
		createDefaultAttribute(data, Attribute.DUE);
		createDefaultAttribute(data, Attribute.STATUS);
		createDefaultAttribute(data, Attribute.POSTPONED);
		createDefaultAttribute(data, Attribute.TASKLIST, client.getRTMListMap());
		createDefaultAttribute(data, Attribute.TASKSERIE);
		createDefaultAttribute(data, Attribute.TASKID);
		createDefaultAttribute(data, Attribute.TAGS);
	}

	private void updateAttributes(TaskData data, RtmTaskSeries series) {
		TaskAttribute attr;
		TaskAttribute root = data.getRoot();

		attr = root.getAttribute(Attribute.TASKLIST.getRTMKey());
		attr.setValue(series.getListId());

		attr = root.getAttribute(Attribute.TASKSERIE.getRTMKey());
		attr.setValue(series.getId());

		if (series.getName() != null) {
			attr = root.getAttribute(Attribute.NAME.getRTMKey());
			attr.setValue(series.getName());
		}

		if (series.getCreated() != null) {
			attr = root.getAttribute(Attribute.CREATED.getRTMKey());
			attr.setValue(Long.toString(series.getCreated().getTime()));
		}

		if (series.getModified() != null) {
			attr = root.getAttribute(Attribute.MODIFIED.getRTMKey());
			attr.setValue(Long.toString(series.getModified().getTime()));
		}


		List<String> tags = series.getTags();
		if (tags != null && !tags.isEmpty()) {
			StringBuffer tagBuffer = new StringBuffer();
			for (String tag: tags) {
				tagBuffer.append(tag);
				tagBuffer.append(", ");
			}
			attr = root.getAttribute(Attribute.TAGS.getRTMKey());
			attr.setValue(tagBuffer.substring(0, tagBuffer.length() - 2));
		}

		RtmTask task = series.getTask();
		if (task != null) {
			attr = root.getAttribute(Attribute.TASKID.getRTMKey());
			attr.setValue(task.getId());

			if (task.getCompleted() != null) {
				attr = root.getAttribute(Attribute.COMPLETED.getRTMKey());
				attr.setValue(Long.toString(task.getCompleted().getTime()));

				attr = root.getAttribute(Attribute.STATUS.getRTMKey());
				attr.setValue("complete");
			} else {
				attr = root.getAttribute(Attribute.STATUS.getRTMKey());
				attr.setValue("incomplete");
			}

			if (task.getPriority() != null) {
				attr = root.getAttribute(Attribute.PRIORITY.getRTMKey());
				switch (task.getPriority()) {
				case High:
					attr.setValue(ITask.PriorityLevel.P1.toString());
					break;
				case Medium:
					attr.setValue(ITask.PriorityLevel.P2.toString());
					break;
				case Low:
					attr.setValue(ITask.PriorityLevel.P4.toString());
					break;
				default:
					attr.setValue(ITask.PriorityLevel.P3.toString());
					break;
				}
			}

			if (task.getDue() != null) {
				attr = root.getAttribute(Attribute.DUE.getRTMKey());
				attr.setValue(Long.toString(task.getDue().getTime()));
			}

			attr = root.getAttribute(Attribute.POSTPONED.getRTMKey());
			attr.setValue(Integer.toString(task.getPostponed()));
		}
	}

	private TaskAttribute createDefaultAttribute(TaskData data, Attribute attribute) {
		TaskAttribute attr = data.getRoot().createAttribute(attribute.getRTMKey());
		TaskAttributeMetaData metaData = attr.getMetaData();
		metaData.setKind(attribute.isHidden() ? null : TaskAttribute.KIND_DEFAULT);
		metaData.setLabel(attribute.toString());
		metaData.setReadOnly(attribute.isReadOnly());
		metaData.setType(attribute.getType());
		return attr;
	}

	private TaskAttribute createDefaultAttribute(TaskData data, Attribute attribute, Map<String, String> listMap) {
		TaskAttribute attr = createDefaultAttribute(data, attribute);
		for (String key : listMap.keySet()) {
			attr.putOption(key, listMap.get(key));
		}
		return attr;
	}
}
